package com.zcl.lambda.test1;

import org.junit.Test;

import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;


/**
 *
 * Lambda的使用
 * 1.举例：(o1,o2) -> Integer.compare(o1,o2)
 * 2.格式：
 *      -> :lambda操作符，或者说箭头操作符
 *      ->左边：Lambda行参列表：就是接口中抽象方法的行参列表
 *      ->右边：Lambda体：就是重写的抽象方法的方法体
 * 3.Lambda表达式的使用：
 *
 * 4.Lambda表达式的本质：作为函数式接口的实例
 *
 * 5.函数式接口：如果一个接口只有一个抽象方法，则说明这个接口是函数式接口@FunctionalInterface
 */
public class LambdaTest1 {


    /**
     *  无参无返回值
     */
    @Test
    public void test1(){
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                System.out.println("无参无返回值");
            }
        };
        //匿名实现类实现接口方法并调用
        r1.run();
        //****************************************************
        // lambda表达方式
        Runnable r2 = ()-> {System.out.println("无参无返回值");};
        //****************************************************
    }

    /**
     * lambda需要一个参数，但是没有返回值
     */
    @Test
    public void test2() {
        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("lambda需要一个参数，但是没有返回值");
        //****************************************************
        // lambda表达方式
        Consumer<String> con2 = (String s)->{System.out.println(s);};
        con2.accept("lambda需要一个参数，但是没有返回值");
        //****************************************************
    }

    /**
     * 数据类型可以省略，因为可以由编译器推断得出，成为"类型推断"
     */
    @Test
    public void test3() {
        Consumer<String> con2 = (String s)->{System.out.println(s);};
        con2.accept("lambda需要一个参数，但是没有返回值");
        // Consumer<String>中定义了String类型，所以s的类型可以由编译器推断出来，可以省略类型
        Consumer<String> con3 = (s)->{System.out.println(s);};
        con3.accept("数据类型可以省略，因为可以由编译器推断得出，成为\"类型推断\"");

    }

    /**
     * lambda 若只需要一个参数，参数的小括号可以省略
     */
    @Test
    public void test4() {
        Consumer<String> con3 = (s)->{System.out.println(s);};
        con3.accept("lambda需要一个参数，但是没有返回值");
        // Consumer<String>中定义了String类型，所以s的类型可以由编译器推断出来，可以省略类型
        Consumer<String> con4 = s-> System.out.println(s);
        con4.accept("lambda 若只需要一个参数，参数的小括号可以省略");
    }

    /**
     * lambda 需要两个或以上的参数，多条执行语句，并且可以有返回值
     */
    @Test
    public void test5() {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(10,20));

        //lambda
        Comparator<Integer> com2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com2.compare(20, 10));
    }

    /**
     * 当Lambda体只有一条语句时，return和大括号若有，则都可以生略
     */
    @Test
    public void test6() {
        Comparator<Integer> com2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };

        Comparator<Integer> com3 = (o1,o2)->(o1.compareTo(o2));
        System.out.println(com3.compare(10,20));
    }

    /**
     * 当Lambda体只有一条语句时，return和大括号若有，则都可以生略
     */
    @Test
    public void test7() {
        Comparator<Integer> com2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };

        Comparator<Integer> com3 = (o1,o2)->(o1.compareTo(o2));
        System.out.println(com3.compare(10,20));
    }

    @Test
    public void test8(){
        List<int[]> collect = IntStream.rangeClosed(1, 100).boxed()
                .flatMap(a -> IntStream.rangeClosed(a, 100)
                        .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0).boxed()
                        .map(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)})).collect(Collectors.toList());
        collect.forEach(t -> System.out.println(t[0] + ", " + t[1] + ", " + t[2]));
    }
}
